CGI、FastCGI和PHP-FPM关系图解

基础
WEB中

Module
了解 CGI 之前,先了解一下Web server 传递数据的另外一种方法:PHP Module加载方式。
以 Apache 为例,在PHP Module方式中,是不是在 Apache 的配置文件 httpd.conf 中加上这样几句:

# 加入以下2句
LoadModule php5_module D:/php/php5apache2_2.dll
AddType application/x-httpd-php .php

# 修改如下内容
<IfModule dir_module>
    DirectoryIndex index.php index.html
</IfModule>

上面是 Windows 下安装php和apache环境后手动配置,在linux下源码安装大致是这样配置的:

# ./configure --with-mysql=/usr/local \
--with-apache=/usr/local/apache \
--enable-track-vars

所以,这种方式,他们的共同本质都是用 LoadModule 来加载 php5_module,就是把php作为apache的一个子模块来运行。
当通过web访问php文件时,apache就会调用php5_module来解析php代码。

那么php5_module是怎么来将数据传给php解析器来解析php代码的呢?答案是通过sapi。
我们再来看一张图,详细的说说apache 与 php 与 sapi的关系:

从上面图中,我们看出了sapi就是这样的一个中间过程,SAPI提供了一个和外部通信的接口,有点类似于socket,使得PHP可以和其他应用进行交互数据(apache,nginx等)。

php默认提供了很多种SAPI,常见的提供给apache和nginx的php5_module、CGI、FastCGI,给IIS的ISAPI,以及Shell的CLI。

所以,以上的apache调用php执行的过程如下:

apache -> httpd -> php5_module -> sapi -> php

这种模式将php模块安装到apache中,所以每一次apache接受请求,都会产生一条进程,这个进程就完整的包括php的各种运算计算等操作。

在上图中,我们很清晰的可以看到,apache每接收一个请求,都会产生一个进程来连接php通过sapi来完成请求,可想而知,如果一旦用户过多,并发数过多,服务器就会承受不住了。

而且,把mod_php编进apache时,出问题时很难定位是php的问题还是apache的问题。

CGI

CGI(Common Gateway Interface)全称是“通用网关接口”,是 Web Server 与 Web Application 之间数据交换的一种协议,其程序须运行在网络服务器上。

CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如php、perl、tcl等。

WEB服务器会传哪些数据给PHP解析器呢?URL、查询字符串、POST数据、HTTP header都会有。

所以,CGI就是规定要传哪些数据,以什么样的格式传递给后方处理这个请求的协议。仔细想想,你在PHP代码中使用的用户从哪里来的。

普通cgi的工作原理

服务器收到请求->请求提交给cgi程序(如php-cgi),cgi程序根据请求提交的参数作应处理(解析php)-> 然后输出标准的html语句 -> 返回给web服服务器,WEB服务器再返回给客户端

优点:完全独立于任何服务器,仅仅是做为中间分子。提供接口给apache和php。他们通过cgi搭线来完成数据传递。这样做的好处了尽量减少2个的关联,使他们2变得更独立。

缺点:每一次web请求都会有启动和退出过程,也就是最为人诟病的fork-and-execute模式,这样一在大规模并发下,就死翘翘了。

FastCGI介绍

从根本上来说,FastCGI是用来提高CGI程序性能的。类似于CGI,FastCGI也可以说是一种协议。

FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去fork一次。

它还支持分布式的运算, 即 FastCGI 程序可以在网站服务器以外的主机上执行,并且接受来自其它网站服务器来的请求。

FastCGI是语言无关的、可伸缩架构的CGI开放扩展,其主要行为是将CGI解释器进程保持在内存中,并因此获得较高的性能。

众所周知,CGI解释器的反复加载是CGI性能低下的主要原因,如果CGI解释器保持在内存中,并接受FastCGI进程管理器调度,则可以提供良好的性能、伸缩性、Fail- Over特性等等。

FastCGI管理器的工作原理

  1. Web Server启动时载入FastCGI进程管理器(Apache Module或IIS ISAPI等)

  2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可建多个php-cgi),并等待来自Web Server的连接。

  3. 当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器。Web server将CGI环境变量和标准输入发送到FastCGI子进程(如php-cgi)。

  4. FastCGI子进程完成处理后,将标准输出和错误信息从同一连接返回Web Server,当FastCGI子进程关闭连接时,请求便告处理完成,FastCGI子进程接着等待,并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中,php-cgi在此便退出了。

FastCGI程序与CGI程序的特点:

CGI:每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展,并重新初始化全部数据结构。

FastCGI:

  1. 只在进程启动时发生一次。一个额外的好处是,持续数据库连接(Persistent database connection)可以工作。

  2. FastCGI是多进程,所以比CGI多线程消耗更多的服务器内存,php-cgi解释器每进程消耗7至25兆内存,将这个数字乘以50或100就是很大的内存数。

PHP-CGI

是对于 CGI 协议的具体实现,用于解析php.ini、载入全部扩展,初始化全部数据结构,php官方出品。

缺点:

  1. php-cgi变更php.ini配置后,需重启php-cgi才能让新的php-ini生效,不可以平滑重启。

  2. 直接杀死php-cgi进程,php就不能运行了。

PHP-FPM介绍

是对于 FastCGI 协议的具体实现,是PHP专用的 FastCGI管理器,用于调度管理PHP解析器 php-cgi 的管理程序,解决了php-cgi的问题。

于2004年由Andrei Nigmatulin(安德烈·尼格马图林)发明,目前,PHP5.3版本之后,PHP-FPM是内置于PHP的。

因为PHP-CGI只是个CGI程序,他自己本身只能解析请求,返回结果,不会进程管理。所以就出现了一些能够调度 php-cgi 进程的程序,比如说由lighthttpd分离出来的spawn-fcgi。

PHP-FPM通过生成新的子进程可以实现php.ini修改后的平滑重启。

总结

所以,如果要搭建一个高性能的PHP WEB服务器,目前最佳的方式是Apache/Nginx + FastCGI + PHP-FPM(+PHP-CGI)